
package businessLogic;

import businessEntities.MainLogger;
import businessEntities.NodeData;
import businessEntities.exceptions.ColumnsQueryException;
import businessEntities.exceptions.ConnectionException;
import businessEntities.exceptions.QueryException;
import dataAccess.DALFileExporter;
import java.io.File;
import java.util.Enumeration;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class BLFileExporter {

    /**
     * @return true if and only if the export succeeded.
     */
    public boolean exportWholeTableToCSV(File outputFile, String dbName, String table) {
        DALFileExporter exporter = new DALFileExporter();
        boolean result;

        try {
            result = exporter.exportWholeTableToCSV(outputFile, dbName, table);
        } catch (ConnectionException | QueryException ex) {
            return false;
        }
        return result;
    }

    /**
     * @return true if and only if the export succeeded.
     */
    public boolean exportFilteredTableToCSV(File outputFile, NodeData nodeData) {

        if (nodeData.isRootFilter()) {
            return exportWholeTableToCSV(outputFile, nodeData.getDataBaseName(), nodeData.getTableName());
        } else {
            boolean result;
            String dataBaseName = nodeData.getDataBaseName();
            String tableName = nodeData.getTableName();
            String where = nodeData.getWhereSentence();
            DALFileExporter exporter = new DALFileExporter();
            try {
                result = exporter.exportFilteredTableToCSV(outputFile, dataBaseName, tableName, where);
            } catch (ConnectionException | QueryException ex) {
                return false;
            }
            return result;
        }
    }

    /**
     * @return true if and only if the export succeeded.
     */
    public boolean exportWholeTableToXML(File outputFile, String dbName, String table) {
        DALFileExporter exporter = new DALFileExporter();
        boolean result;

        try {
            result = exporter.exportWholeTableToXML(outputFile, dbName, table);
        } catch (ConnectionException | QueryException | ColumnsQueryException ex) {
            return false;
        }
        return result;
    }

    /**
     * @return true if and only if the export succeeded.
     */
    public boolean exportFilteredTableToXML(File outputFile, NodeData nodeData) {

        if (nodeData.isRootFilter()) {
            return exportWholeTableToXML(outputFile, nodeData.getDataBaseName(), nodeData.getTableName());
        } else {
            boolean result;
            String dataBaseName = nodeData.getDataBaseName();
            String tableName = nodeData.getTableName();
            String where = nodeData.getWhereSentence();
            DALFileExporter exporter = new DALFileExporter();
            try {
                result = exporter.exportFilteredTableToXML(outputFile, dataBaseName, tableName, where);
            } catch (ConnectionException | QueryException | ColumnsQueryException ex) {
                return false;
            }
            return result;
        }
    }
    
    /**
     * Save tree to file
     * @return true if and only if no error occurred during the process.
     */
    public boolean saveTreeToFile(JTree tree, File outFile){
        
        boolean answer = false;
        DefaultTreeModel treeModel = (DefaultTreeModel)tree.getModel(); 
        try {
            
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.newDocument();
            
            //Main Element
            Element  mainElement = doc.createElement("Tree");
            doc.appendChild(mainElement);
            
            if(treeModel.getRoot() != null){
                DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode)treeModel.getRoot();
                NodeData rootData = (NodeData)rootNode.getUserObject();
                
                //Root Element
                Element root = doc.createElement("Root");
                root.setAttribute("depth", ""+0);
                mainElement.appendChild(root);
                Element table = doc.createElement("Table");
                table.appendChild(doc.createTextNode(rootData.getTableName()));
                Element database = doc.createElement("Database");
                database.appendChild(doc.createTextNode(rootData.getDataBaseName()));
                root.appendChild(database);
                root.appendChild(table);
               
                if (rootNode.getChildCount() > 0) {
                    addChildren(rootNode, doc, root, 0);
                }   
            }
                       
                DALFileExporter exporter = new DALFileExporter();
                answer = exporter.saveTreeToFile(doc, outFile);
                
        } catch (ParserConfigurationException | NullPointerException ex) {
            MainLogger.logger.error("Tree structure could not be parsed.",ex);
            answer = false;
        }          
        return answer;
    }

    private void addChildren(DefaultMutableTreeNode node, Document doc, Element element, int depth) {
        if (node == null || node.getChildCount() < 1) {
            return;
        }
        for (Enumeration e = node.children(); e.hasMoreElements();) {
            DefaultMutableTreeNode child = (DefaultMutableTreeNode) e.nextElement();
            NodeData data = (NodeData) child.getUserObject();
            Element nextElement = addChildToDocument(data, doc, element,depth+1);
            addChildren(child, doc, nextElement, depth+1);
        }
    }

    private Element addChildToDocument(NodeData data, Document doc, Element parent, int depth) {
        
        Element newElemnt = doc.createElement("Child");
        newElemnt.setAttribute("depth", ""+depth);
        Element filter = doc.createElement("Filter");
        filter.appendChild(doc.createTextNode(data.getCurrentFilter()));
        parent.appendChild(newElemnt);
        newElemnt.appendChild(filter);
        return newElemnt;
    }
    
}
